/**
 * Copyright 2019-2024 覃海林(qinhaisenlin@163.com).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */ 
package com.qinhailin.common.util;

import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
import org.apache.commons.codec.binary.Base64;

/**
 * RSA非对称加密
 * @author qinhailin
 *
 */
public class RsaUtil {
	
	// 缓存的 RSA 密钥对  
    private static RsaKeyPair rsaKeyPair;  

	public static void main(String[] args) throws Exception {
		try {
			rsaKeyPair=generateKeyPair();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 获取或生成 RSA 密钥对  
	 * @return
	 * @throws NoSuchAlgorithmException
	 */
    public static RsaKeyPair getGenerateKeyPair() {  
        if (rsaKeyPair == null) {  
            try {
				rsaKeyPair = generateKeyPair();
			} catch (NoSuchAlgorithmException e) {
				e.printStackTrace();
			}  
        }  
        return rsaKeyPair;  
    }  
    
    /**
     * 公钥加密
     * 
     * @param text 待加密的文本
     * @return 加密后的文本
     * @throws Exception
     */
    public static String encryptByPublicKey(String text) throws Exception {
    	return encryptByPublicKey(getGenerateKeyPair().publicKey, text);
    }
    
    /**
     * 私钥解密
     * 
     * @param text 待解密的文本
     * @return 解密后的文本
     * @throws Exception
     */
    public static String decryptByPrivateKey(String text) throws Exception {
    	return decryptByPrivateKey(getGenerateKeyPair().privateKey, text);
    }


	/**
	 * 私钥解密
	 *
	 * @param privateKeyString 私钥
	 * @param text             待解密的文本
	 * @return 解密后的文本
	 */
    private static String decryptByPrivateKey(String privateKeyString, String text) throws Exception {
		PKCS8EncodedKeySpec pkcs8EncodedKeySpec5 = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyString));
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec5);
		Cipher cipher = Cipher.getInstance("RSA");
		cipher.init(Cipher.DECRYPT_MODE, privateKey);
		byte[] result = cipher.doFinal(Base64.decodeBase64(text));
		return new String(result);
	}

	/**
	 * 公钥加密
	 *
	 * @param publicKeyString 公钥
	 * @param text            待加密的文本
	 * @return 加密后的文本
	 */
	private static String encryptByPublicKey(String publicKeyString, String text) throws Exception {
		X509EncodedKeySpec x509EncodedKeySpec2 = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyString));
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec2);
		Cipher cipher = Cipher.getInstance("RSA");
		cipher.init(Cipher.ENCRYPT_MODE, publicKey);
		byte[] result = cipher.doFinal(text.getBytes());
		return Base64.encodeBase64String(result);
	}

	/**
	 * 构建RSA密钥对
	 *
	 * @return 生成后的公私钥信息
	 */
	private static RsaKeyPair generateKeyPair() throws NoSuchAlgorithmException {
		KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
		keyPairGenerator.initialize(1024);
		KeyPair keyPair = keyPairGenerator.generateKeyPair();
		RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
		RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
		String publicKeyString = Base64.encodeBase64String(rsaPublicKey.getEncoded());
		String privateKeyString = Base64.encodeBase64String(rsaPrivateKey.getEncoded());
		System.out.println("公钥=" + publicKeyString);
		System.out.println("私钥=" + privateKeyString);
		rsaKeyPair = new RsaKeyPair(publicKeyString, privateKeyString);
		return rsaKeyPair;
	}

	/**
	 * RSA密钥对对象
	 */
	public static class RsaKeyPair {
		private final String publicKey;
		private final String privateKey;

		public RsaKeyPair(String publicKey, String privateKey) {
			this.publicKey = publicKey;
			this.privateKey = privateKey;
		}

		public String getPublicKey() {
			return publicKey;
		}

		public String getPrivateKey() {
			return privateKey;
		}
	}

}
